package it.cagiobox.fileutility.gui;

import it.cagiobox.fileutility.bo.MatchingGrid;
import it.cagiobox.fileutility.pub.SectionMatchingMarker;

import java.awt.EventQueue;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import java.awt.BorderLayout;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import java.awt.CardLayout;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JLabel;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;

import javax.swing.AbstractButton;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.RowFilter;

import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.swing.JFileChooser;
import javax.swing.JTable;
import javax.swing.JCheckBox;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.JScrollPane;
import java.awt.Color;
import javax.swing.JCheckBoxMenuItem;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.Font;

public class IniFileComparer {
	private static Logger log = LogManager.getLogger(IniFileComparer.class);

	private int major = 0;
	private int minor = 0;
	private String revision = "9b";

	private JFrame frame;
	private JMenuBar menuBar = new JMenuBar();
	private JMenu mnFile = new JMenu("File");
	private JMenuItem mntmOpen = new JMenuItem("Open");

	private JPanel appPanel = new JPanel();
	private JPanel emptyPanel = new JPanel();
	private JPanel inputFilePanel = new JPanel();
	private JPanel gridPanel = new JPanel();

	private final String EMPTY_PANEL = "emptyPanel";
	private final String GRID_PANEL = "gridPanel";
	private final String INPUTFILE_PANEL = "inputFilePanel";

	private JLabel lblLeftFile = new JLabel("Left file");
	private JLabel lblRightFile = new JLabel("Right file");
	private JTextField textLeftFile = new JTextField(
			".\\test\\it\\cagiobox\\fileutility\\test\\files\\pdl_left.ini");
	private JTextField textRightFile = new JTextField(
			".\\test\\it\\cagiobox\\fileutility\\test\\files\\pdl_right.ini");
	private JButton btnRightFile = new JButton("...");
	private JButton btnLeftFile = new JButton("...");
	private JButton btnLaunchCompare = new JButton("Ok");
	private JTable table = new JTable();
	private final JLabel lblWriteOutputTo = new JLabel("Write output to file");
	private final JCheckBox checkBox = new JCheckBox("");
	private final JTextField textOutputFile = new JTextField();
	private final JMenuItem mntmExit = new JMenuItem("Exit");
	private final JMenu mnTools = new JMenu("Tools");
	private final JMenu mnHelp = new JMenu("Help");
	private final JMenuItem mntmHowTo = new JMenuItem("How to...");
	private final JMenuItem mntmAbout = new JMenuItem("About");

	private it.cagiobox.fileutility.IniFileComparer ifc = null;
	private final JScrollPane scrollPane = new JScrollPane();
	private final JButton btnOutputFile = new JButton("...");
	private final JMenu mnView = new JMenu("View");
	private final JCheckBoxMenuItem chckbxmntmLeftOnly = new JCheckBoxMenuItem(
			"Left only");
	private final JCheckBoxMenuItem chckbxmntmRightOnly = new JCheckBoxMenuItem(
			"Right only");
	private final JCheckBoxMenuItem chckbxmntmIdentical = new JCheckBoxMenuItem(
			"Identical");
	private final JCheckBoxMenuItem chckbxmntmDifferent = new JCheckBoxMenuItem(
			"Different");
	private final JCheckBoxMenuItem chckbxmntmWhiteLines = new JCheckBoxMenuItem(
			"White lines");
	private final JButton btnCancelCompare = new JButton("Cancel");
	private final JCheckBoxMenuItem chckbxmntmEqualSection = new JCheckBoxMenuItem(
			"Equal sections");
	private final JCheckBoxMenuItem chckbxmntmDifferentSections = new JCheckBoxMenuItem(
			"Different sections");
	private final JCheckBoxMenuItem chckbxmntmLeftOnlySections = new JCheckBoxMenuItem(
			"Left only sections");
	private final JCheckBoxMenuItem chckbxmntmRightOnlySections = new JCheckBoxMenuItem(
			"Right only sections");

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					log.info("Now let's start the gui...");

					IniFileComparer window = new IniFileComparer();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public IniFileComparer() {
		initialize();
	}

	private String LookForFile(String initialPath) {
		String retPath = initialPath;

		// a file chooser to search for disk files
		JFileChooser fileChooser = new JFileChooser();

		File dir = null;

		// if something already written, I try to see if exists the directory
		if (!initialPath.trim().equals("")) {
			dir = new File(initialPath.trim());
			if (dir.exists()) {
				dir = new File(dir.getPath());
			}
		}

		// if not already set, I'm going to position on the current directory
		if (dir == null) {
			dir = new File(System.getProperty("user.dir"));
		}

		fileChooser.setCurrentDirectory(dir);

		// now fileChooser will play its part
		int returnVal = fileChooser.showOpenDialog(appPanel);

		if (returnVal == JFileChooser.APPROVE_OPTION) {

			// user has selected a file
			File file = fileChooser.getSelectedFile();

			try {
				retPath = file.getCanonicalPath();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();

				JOptionPane.showMessageDialog(
						appPanel,
						"Errore durante recupero percorso del file:\r\n"
								+ e.getMessage(), "Errore",
						JOptionPane.ERROR_MESSAGE);

			}
		} else {
			// user has abandoned the selection
		}

		return retPath;

	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		textOutputFile.setEnabled(false);
		textOutputFile.setColumns(10);
		frame = new JFrame();
		frame.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent arg0) {
				close(frame);
			}
		});
		frame.setBounds(100, 100, 450, 471);
		frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		frame.getContentPane().setLayout(new BorderLayout(0, 0));

		frame.getContentPane().add(menuBar, BorderLayout.NORTH);

		// frame icon
		BufferedImage image = null;
		URL urlIcon = frame.getClass().getResource(
				"/resources/compare_icon.gif");
		try {
			image = ImageIO.read(urlIcon);
		} catch (IOException e) {
			e.printStackTrace();
		}
		frame.setIconImage(image);

		// frame title
		frame.setTitle("  IniFileComparer");

		menuBar.add(mnFile);
		mntmOpen.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				// show input file panel
				CardLayout cards = (CardLayout) appPanel.getLayout();
				cards.show(appPanel, INPUTFILE_PANEL);
			}
		});

		mnFile.add(mntmOpen);
		mntmExit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				close(frame);
			}
		});

		mnFile.add(mntmExit);
		mnTools.setEnabled(false);

		menuBar.add(mnTools);
		mnView.setEnabled(false);

		menuBar.add(mnView);
		chckbxmntmIdentical.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				applyFilter();
			}
		});
		chckbxmntmWhiteLines.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				applyFilter();
			}
		});
		chckbxmntmEqualSection.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				applyFilter();
			}
		});
		chckbxmntmEqualSection.setSelected(true);

		mnView.add(chckbxmntmEqualSection);
		chckbxmntmDifferentSections.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				applyFilter();
			}
		});
		chckbxmntmDifferentSections.setSelected(true);

		mnView.add(chckbxmntmDifferentSections);
		chckbxmntmLeftOnlySections.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				applyFilter();
			}
		});
		chckbxmntmLeftOnlySections.setSelected(true);

		mnView.add(chckbxmntmLeftOnlySections);
		chckbxmntmRightOnlySections.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				applyFilter();
			}
		});
		chckbxmntmRightOnlySections.setSelected(true);

		mnView.add(chckbxmntmRightOnlySections);
		chckbxmntmWhiteLines.setSelected(true);

		mnView.add(chckbxmntmWhiteLines);

		mnView.add(chckbxmntmIdentical);
		chckbxmntmDifferent.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				applyFilter();
			}
		});

		mnView.add(chckbxmntmDifferent);
		chckbxmntmLeftOnly.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				applyFilter();
			}
		});

		mnView.add(chckbxmntmLeftOnly);
		chckbxmntmRightOnly.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				applyFilter();
			}
		});

		mnView.add(chckbxmntmRightOnly);

		menuBar.add(mnHelp);

		mnHelp.add(mntmHowTo);
		mntmAbout.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				JOptionPane.showMessageDialog(appPanel, "     Versione: "
						+ major + "." + minor + "." + revision,
						"About IniFileComparer",
						JOptionPane.INFORMATION_MESSAGE);

			}
		});

		mnHelp.add(mntmAbout);

		frame.getContentPane().add(appPanel, BorderLayout.CENTER);
		appPanel.setLayout(new CardLayout(0, 0));

		emptyPanel.setName(EMPTY_PANEL);
		appPanel.add(emptyPanel, EMPTY_PANEL);

		inputFilePanel.setName(INPUTFILE_PANEL);
		appPanel.add(inputFilePanel, INPUTFILE_PANEL);
		GridBagLayout gbl_inputFilePanel = new GridBagLayout();
		gbl_inputFilePanel.columnWidths = new int[] { 25, 72, 231, 75, 18, 0 };
		gbl_inputFilePanel.rowHeights = new int[] { 0, 44, 44, 0, 36, 0, 0 };
		gbl_inputFilePanel.columnWeights = new double[] { 0.0, 0.0, 1.0, 0.0,
				0.0, Double.MIN_VALUE };
		gbl_inputFilePanel.rowWeights = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0,
				0.0, Double.MIN_VALUE };
		inputFilePanel.setLayout(gbl_inputFilePanel);

		GridBagConstraints gbc_lblNewLabel = new GridBagConstraints();
		gbc_lblNewLabel.anchor = GridBagConstraints.WEST;
		gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5);
		gbc_lblNewLabel.gridx = 1;
		gbc_lblNewLabel.gridy = 1;
		inputFilePanel.add(lblLeftFile, gbc_lblNewLabel);

		textLeftFile.setColumns(10);
		GridBagConstraints gbc_textLeftFile = new GridBagConstraints();
		gbc_textLeftFile.fill = GridBagConstraints.HORIZONTAL;
		gbc_textLeftFile.insets = new Insets(0, 0, 5, 5);
		gbc_textLeftFile.gridx = 2;
		gbc_textLeftFile.gridy = 1;
		inputFilePanel.add(textLeftFile, gbc_textLeftFile);

		btnLeftFile.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String path;
				if (!textLeftFile.getText().trim().equals("")) {
					path = LookForFile(textLeftFile.getText());
				} else if (!textRightFile.getText().trim().equals("")) {
					path = LookForFile(textRightFile.getText());
				} else {
					path = LookForFile("");
				}

				textLeftFile.setText(path);
			}
		});
		GridBagConstraints gbc_btnLeftFile = new GridBagConstraints();
		gbc_btnLeftFile.insets = new Insets(0, 0, 5, 5);
		gbc_btnLeftFile.gridx = 3;
		gbc_btnLeftFile.gridy = 1;
		inputFilePanel.add(btnLeftFile, gbc_btnLeftFile);

		GridBagConstraints gbc_lblNewLabel_1 = new GridBagConstraints();
		gbc_lblNewLabel_1.anchor = GridBagConstraints.WEST;
		gbc_lblNewLabel_1.fill = GridBagConstraints.VERTICAL;
		gbc_lblNewLabel_1.insets = new Insets(0, 0, 5, 5);
		gbc_lblNewLabel_1.gridx = 1;
		gbc_lblNewLabel_1.gridy = 2;
		inputFilePanel.add(lblRightFile, gbc_lblNewLabel_1);
		textRightFile.setColumns(10);

		GridBagConstraints gbc_textField_1 = new GridBagConstraints();
		gbc_textField_1.fill = GridBagConstraints.HORIZONTAL;
		gbc_textField_1.insets = new Insets(0, 0, 5, 5);
		gbc_textField_1.gridx = 2;
		gbc_textField_1.gridy = 2;
		inputFilePanel.add(textRightFile, gbc_textField_1);

		GridBagConstraints gbc_btnRightFile = new GridBagConstraints();
		gbc_btnRightFile.insets = new Insets(0, 0, 5, 5);
		gbc_btnRightFile.gridx = 3;
		gbc_btnRightFile.gridy = 2;
		btnRightFile.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String path;
				if (!textRightFile.getText().trim().equals("")) {
					path = LookForFile(textRightFile.getText());
				} else if (!textLeftFile.getText().trim().equals("")) {
					path = LookForFile(textLeftFile.getText());
				} else {
					path = LookForFile("");
				}
				textRightFile.setText(path);
			}

		});
		inputFilePanel.add(btnRightFile, gbc_btnRightFile);
		btnLaunchCompare.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				File checkFile;

				checkFile = new File(textLeftFile.getText());
				if (!checkFile.exists() || checkFile.isDirectory()) {
					JOptionPane.showMessageDialog(inputFilePanel,
							"Percorso del file di sinistra non valido");
					textLeftFile.requestFocusInWindow();
					return;
				}

				checkFile = new File(textRightFile.getText());
				if (!checkFile.exists() || checkFile.isDirectory()) {
					JOptionPane.showMessageDialog(inputFilePanel,
							"Percorso del file di destra non valido");
					textRightFile.requestFocusInWindow();
					return;
				}

				if (checkBox.isSelected()) {
					checkFile = new File(textOutputFile.getText());
					if (!checkFile.exists() || checkFile.isDirectory()) {
						JOptionPane.showMessageDialog(inputFilePanel,
								"Percorso del file di output non valido");
						textOutputFile.requestFocusInWindow();
						return;
					}
				}

				// if all files exist, go on with compare
				ifc = new it.cagiobox.fileutility.IniFileComparer();
				try {
					ifc.compare(textLeftFile.getText(),
							textRightFile.getText(), textOutputFile.getText(),
							false);

					// initialize table model
					TableModel tm = new GridTableModel(ifc.getColumnNames(),
							ifc.getData());

					// assign model to table
					table.setModel(tm);

					// hilite header
					JTableHeader header = table.getTableHeader();
					header.setBackground(Color.yellow);

					// set column width
					// hide match type column, it will be used by filter
					// table.getColumnModel().getColumn(0).setMaxWidth(0);
					// table.getColumnModel().getColumn(0).setMinWidth(0);
					// table.getColumnModel().getColumn(0).setPreferredWidth(0);

					// resize row number columns
					table.getColumnModel().getColumn(1).setMaxWidth(30);
					table.getColumnModel().getColumn(1).setMinWidth(30);
					table.getColumnModel().getColumn(1).setPreferredWidth(30);

					table.getColumnModel().getColumn(4).setMaxWidth(30);
					table.getColumnModel().getColumn(4).setMinWidth(30);
					table.getColumnModel().getColumn(4).setPreferredWidth(30);

					// enable View menu for filtering
					mnView.setEnabled(true);

					// apply filter as for view menu
					applyFilter();

					// show table card
					CardLayout cards = (CardLayout) appPanel.getLayout();
					cards.show(appPanel, GRID_PANEL);

				} catch (Exception e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();

					JOptionPane.showMessageDialog(appPanel, e1.getMessage(),
							"Errore", JOptionPane.ERROR_MESSAGE);
				}
			}
		});

		GridBagConstraints gbc_lblWriteOutputTo = new GridBagConstraints();
		gbc_lblWriteOutputTo.anchor = GridBagConstraints.EAST;
		gbc_lblWriteOutputTo.insets = new Insets(0, 0, 5, 5);
		gbc_lblWriteOutputTo.gridx = 2;
		gbc_lblWriteOutputTo.gridy = 3;
		inputFilePanel.add(lblWriteOutputTo, gbc_lblWriteOutputTo);

		GridBagConstraints gbc_checkBox = new GridBagConstraints();
		gbc_checkBox.anchor = GridBagConstraints.WEST;
		gbc_checkBox.insets = new Insets(0, 0, 5, 5);
		gbc_checkBox.gridx = 3;
		gbc_checkBox.gridy = 3;
		checkBox.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent actionEvent) {
				AbstractButton abstractButton = (AbstractButton) actionEvent
						.getSource();

				textOutputFile.setEnabled(abstractButton.getModel()
						.isSelected());
			}
		});
		inputFilePanel.add(checkBox, gbc_checkBox);

		GridBagConstraints gbc_textOutputFile = new GridBagConstraints();
		gbc_textOutputFile.insets = new Insets(0, 0, 5, 5);
		gbc_textOutputFile.fill = GridBagConstraints.HORIZONTAL;
		gbc_textOutputFile.gridx = 2;
		gbc_textOutputFile.gridy = 4;
		inputFilePanel.add(textOutputFile, gbc_textOutputFile);

		GridBagConstraints gbc_btnOutputFile = new GridBagConstraints();
		gbc_btnOutputFile.insets = new Insets(0, 0, 5, 5);
		gbc_btnOutputFile.gridx = 3;
		gbc_btnOutputFile.gridy = 4;
		btnOutputFile.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
			}
		});
		btnOutputFile.setEnabled(false);
		inputFilePanel.add(btnOutputFile, gbc_btnOutputFile);

		GridBagConstraints gbc_btnCancelCompare = new GridBagConstraints();
		gbc_btnCancelCompare.anchor = GridBagConstraints.EAST;
		gbc_btnCancelCompare.insets = new Insets(0, 0, 0, 5);
		gbc_btnCancelCompare.gridx = 2;
		gbc_btnCancelCompare.gridy = 5;
		btnCancelCompare.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				if (table.getRowCount() > 0) {
					// back to table card
					CardLayout cards = (CardLayout) appPanel.getLayout();
					cards.show(appPanel, GRID_PANEL);

				} else {
					// back to empty card
					CardLayout cards = (CardLayout) appPanel.getLayout();
					cards.show(appPanel, EMPTY_PANEL);
				}
			}
		});
		inputFilePanel.add(btnCancelCompare, gbc_btnCancelCompare);

		GridBagConstraints gbc_btnLaunchCompare = new GridBagConstraints();
		gbc_btnLaunchCompare.insets = new Insets(0, 0, 0, 5);
		gbc_btnLaunchCompare.gridx = 3;
		gbc_btnLaunchCompare.gridy = 5;
		inputFilePanel.add(btnLaunchCompare, gbc_btnLaunchCompare);

		gridPanel.setName(GRID_PANEL);
		appPanel.add(gridPanel, GRID_PANEL);
		gridPanel.setLayout(new BorderLayout(0, 0));
		table.setFont(new Font("Consolas", Font.PLAIN, 12));

		scrollPane.add(table);

		gridPanel.add(scrollPane, BorderLayout.CENTER);

		scrollPane.setViewportView(table);

	}

	private void close(JFrame f) {
		int resp = JOptionPane.showConfirmDialog(f,
				"Sei sicuro di volere uscire?", "Chiusura applicazione",
				JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);

		if (resp == JOptionPane.YES_OPTION) {
			// System.exit(0);
			f.dispose();
		} else {

		}

	}

	private void applyFilter() {
		RowFilter<Object, Object> filter = new RowFilter<Object, Object>() {
			public boolean include(Entry entry) {

				log.trace("RowFilter.include:" + entry.getValue(1).toString()
						+ " " + entry.getValue(2).toString() + " "
						+ entry.getValue(3).toString() + " "
						+ entry.getValue(4).toString() + " "
						+ entry.getValue(5).toString() + " "
						+ entry.getValue(6).toString());

				// if filter is per sections
				if (entry.getValue(0) != null
						&& (chckbxmntmEqualSection.isSelected()
								|| chckbxmntmLeftOnlySections.isSelected()
								|| chckbxmntmRightOnlySections.isSelected() || chckbxmntmDifferentSections
									.isSelected())) {

					if (entry.getValue(0).equals(SectionMatchingMarker.EQUAL))
						return chckbxmntmEqualSection.isSelected();

					if (entry.getValue(0).equals(
							SectionMatchingMarker.LEFTONLYSECT))
						return chckbxmntmLeftOnlySections.isSelected();

					if (entry.getValue(0).equals(
							SectionMatchingMarker.RIGHTONLYSECT))
						return chckbxmntmRightOnlySections.isSelected();

					if (entry.getValue(0).equals(
							SectionMatchingMarker.DIFFERENTPROPS)
							|| entry.getValue(0).equals(
									SectionMatchingMarker.DIFFERENTVALS))
						return chckbxmntmDifferentSections.isSelected();

				} else {

					if (entry.getValue(1) == "=")
						return chckbxmntmIdentical.isSelected();
					if (entry.getValue(1) == "L")
						return chckbxmntmLeftOnly.isSelected();
					if (entry.getValue(1) == "R")
						return chckbxmntmRightOnly.isSelected();
					if (entry.getValue(1) == "!")
						return chckbxmntmDifferent.isSelected();
					if (entry.getValue(1) == " ")
						return chckbxmntmWhiteLines.isSelected();
				}
				return true;
			}
		};
		TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(
				table.getModel());
		sorter.setRowFilter(filter);
		table.setRowSorter(sorter);

	}
}
